package com.zy.hash.consistent;

import lombok.Data;

import java.util.List;
import java.util.stream.Collectors;

/**
 * @author zhaoyi
 * @date 2021/7/21 15:58
 */
@Data
public class VirtualNodeManager {
    private List<VirtualNode> virtualNodes;
    //已经上线的节点数
    private volatile int cacheCount;


    //上线节点
    public synchronized void up(CacheNode cacheNode) {

        if (cacheCount >= (virtualNodes.size() - 1)) {
            throw new IllegalArgumentException("太多缓存节点了");
        }

        if (cacheCount == 0) {
            System.out.println("!!! 上线第 1 个节点");
            for (VirtualNode vn : virtualNodes) {
                vn.setCacheNode(cacheNode);
            }
            setCacheCount(cacheCount + 1);
            return;
        }
        setCacheCount(cacheCount + 1);
        System.out.println("上线第 " + cacheNode + " 个节点");
        for (int i = 0; i < virtualNodes.size(); i += cacheCount) {
            VirtualNode v = virtualNodes.get(i);
            v.setCacheNode(cacheNode);
        }

    }


    public void put(String key, Object value) {
        if (cacheCount == 0) {
            throw new IllegalArgumentException("缓存实例未添加");
        }
        int i = key.hashCode();
        for (VirtualNode v : virtualNodes) {
            if (v.getMax().compareTo(i) > 0) {
                CacheNode cacheNode = v.getCacheNode();
                cacheNode.put(key, value);
                System.out.println("放入实例 " + cacheNode.getName());
                return;
            }
        }
    }


    public Object get(String key) {
        int i = key.hashCode();
        for (VirtualNode v : virtualNodes) {
            if (v.getMax().compareTo(i) > 0) {
                CacheNode cacheNode = v.getCacheNode();
                return cacheNode.get(key);
            }
        }
        return null;
    }

    //模拟下线了一个节点
    public void down() {
        CacheNode cn = virtualNodes.get(0).getCacheNode();
        setCacheCount(cacheCount - 1);

        List<CacheNode> collect = virtualNodes.stream().filter(f -> !cn.equals(f.getCacheNode()))
                .map(VirtualNode::getCacheNode).distinct().collect(Collectors.toList());

        for (int i = 0; i < virtualNodes.size(); i++) {
            VirtualNode node = virtualNodes.get(i);
            CacheNode cacheNode = node.getCacheNode();
            if (cn.equals(cacheNode)) {
                int j = i > (collect.size() - 1) ? i % (collect.size() - 1) : i;
                node.setCacheNode(collect.get(j));
            }
        }


    }
}
